package co.edu.uniandes.sd.mundo;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.net.URI;
import java.security.Key;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;

import net.jxta.discovery.DiscoveryEvent;
import net.jxta.discovery.DiscoveryListener;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.Advertisement;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.Element;
import net.jxta.document.MimeMediaType;
import net.jxta.endpoint.InputStreamMessageElement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.id.IDFactory;
import net.jxta.peergroup.PeerGroup;
import net.jxta.pipe.OutputPipe;
import net.jxta.pipe.OutputPipeEvent;
import net.jxta.pipe.OutputPipeListener;
import net.jxta.pipe.PipeID;
import net.jxta.pipe.PipeMsgEvent;
import net.jxta.pipe.PipeMsgListener;
import net.jxta.pipe.PipeService;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.rendezvous.RendezVousService;
import net.jxta.rendezvous.RendezvousEvent;
import net.jxta.rendezvous.RendezvousListener;


public class ComunicacionesNodo implements PipeMsgListener,DiscoveryListener,OutputPipeListener,RendezvousListener{

	private final static String NOMBRE_PIPE = "pipeRecepcion";
	
	private Nodo nodo;

	private NetworkManager networkManager;
	
	private PeerGroup peerGroup;
	
	private DiscoveryService discoveryService;
	
	private PipeService pipeService;
	
	private PipeAdvertisement inputPipe;

	private AdvertisementNodo advertisementNodo;
	
	private AdvertisementModificacion advertisementModificacion;
	
	private Hashtable<Integer,Message> consultasPendientes;
	
	private Hashtable<Integer,Message> mensajesPendientes;
	
	private int numMensaje;
	
	public ComunicacionesNodo(Nodo nodo){
		this.nodo = nodo;
		consultasPendientes = new Hashtable<Integer, Message>();
		mensajesPendientes = new Hashtable<Integer, Message>();
		try{
			networkManager = new NetworkManager(NetworkManager.ConfigMode.ADHOC,nodo.getNombre(), new File(new File(".cache"),nodo.getNombre()).toURI());
			networkManager.startNetwork();
			numMensaje = 0;
		}catch (Exception e) {
			// TODO Manejar excepcion
			e.printStackTrace();
		}
		
		AdvertisementFactory.registerAdvertisementInstance(AdvertisementNodo.TIPO_ADVERTISEMENT,new Instantiator());
		AdvertisementFactory.registerAdvertisementInstance(AdvertisementModificacion.TIPO_ADVERTISEMENT,new InstantiatorModificacion());
		
		peerGroup = networkManager.getNetPeerGroup();
		discoveryService = peerGroup.getDiscoveryService();
		pipeService = peerGroup.getPipeService();
		
		RendezVousService rdvSvc = peerGroup.getRendezVousService();
		// Register a rendezvous listener
		rdvSvc.addListener(this);
		
		inputPipe = crearPipeAdv();
		System.out.println("PIPE ID :"+inputPipe.getID().toString());
		try{
			pipeService.createInputPipe(inputPipe, this);
		}catch (Exception e) {
			e.printStackTrace();
		}
		advertisementNodo= new AdvertisementNodo();
		advertisementNodo.setIdentificadoresDocumento("");
		advertisementNodo.setPalabrasClave("");
		advertisementNodo.setPipeAdvertisement(inputPipe);
		
		try{
			discoveryService.publish(advertisementNodo);
		}catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	public PipeAdvertisement getInputPipe() {
		return inputPipe;
	}

	public void setInputPipe(PipeAdvertisement inputPipe) {
		this.inputPipe = inputPipe;
	}
	
	private PipeAdvertisement crearPipeAdv(){
		PipeAdvertisement pipeAdv =  (PipeAdvertisement)AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType());
		
		
		pipeAdv.setPipeID(IDFactory.newPipeID(peerGroup.getPeerGroupID()));
		pipeAdv.setName(NOMBRE_PIPE);
		pipeAdv.setType(PipeService.UnicastType);
		
		
		return pipeAdv;
	}
	
	@Override
	public void pipeMsgEvent(PipeMsgEvent event) {
		Message msg = null;
		try {
			// grab the message from the event
			msg = event.getMessage();
			if (msg == null)
				return;
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
		
		ThreadManejoMensajes thread = new ThreadManejoMensajes(nodo, msg);
		thread.start();
		
	};

	@Override
	public void discoveryEvent(DiscoveryEvent event) {
		System.out.println("Found something!");
		Message msg = consultasPendientes.get(event.getQueryID());
		if(msg == null){
			return;
		}
		Enumeration<Advertisement> respuestas = event.getSearchResults();
        while (respuestas.hasMoreElements()) {

            Object advertTemp = respuestas.nextElement();
            System.out.println(advertTemp.getClass());
            if(advertTemp instanceof AdvertisementNodo){
            	AdvertisementNodo nodo = (AdvertisementNodo)advertTemp;
            	PipeAdvertisement adv = nodo.getPipeAdvertisement();
            	try{
            		System.out.println(adv.getID());
            		//OutputPipe output = pipeService.createOutputPipe(adv,0);
            		int n = numMensaje++;
            		mensajesPendientes.put(n, msg);
            		solicitudAutenticacion(adv,n);
            		
            		//Message m2 = crearSobre(msg);
            		
            		//output.send(m2.clone());
            		System.out.println("Succeeded");
            	}catch (Exception e) {
            		e.printStackTrace();
				}
            }
            if(advertTemp instanceof AdvertisementModificacion){
            	AdvertisementModificacion nodo = (AdvertisementModificacion)advertTemp;
            	PipeAdvertisement adv = nodo.getPipeAdvertisement();
            	try{
            		if(msg.getMessageElement(Nodo.COMANDO).toString().equals(Nodo.PEDIR_PERMISO)){
            			if(!adv.getID().toString().equals(inputPipe.getID().toString())){
            				System.out.println("Pido permiso a: "+adv.getID());
            				this.nodo.agregarNodoConflictoModificacion(msg.getMessageElement(Nodo.CONTENIDO).toString(), adv.getID().toString());
            			}
            		}
            		System.out.println(adv.getID());
            		/*OutputPipe output = pipeService.createOutputPipe(adv,0);
            		Message m2 = crearSobre(msg);
            		output.send(m2.clone());
            		*/
            		int n = numMensaje++;
            		mensajesPendientes.put(n, msg);
            		solicitudAutenticacion(adv,n);
            		System.out.println("Succeeded");
            	}catch (Exception e) {
            		e.printStackTrace();
				}
            }
        }
        
        if (msg.getMessageElement(Nodo.COMANDO).equals(Nodo.PEDIR_PERMISO)){
        	nodo.revisarEstadoModificacion();
        }
		
	}



	@Override
	public void outputPipeEvent(OutputPipeEvent event) {
		System.out.println("Got an output pipe event");
		OutputPipe op = event.getOutputPipe();
		Message msg = null;
		// create message, and send it via the output pipe
		try {
			System.out.println("Sending message");
			Date date = new Date(System.currentTimeMillis());
			String myMsg = "Hello from peer " + peerGroup.getPeerName()
					+ "[" + date.toString() + "]";
			msg = new Message();
			StringMessageElement sme = new StringMessageElement("FileSending", myMsg,
					null);
			
			MessageElement me = new InputStreamMessageElement("FileSending", MimeMediaType.TEXT_DEFAULTENCODING, new FileInputStream(new File("data/test.txt")), sme);
			
			msg.addMessageElement(null, me);
			
			op.send(msg);
		} catch (Exception e) {
			System.out.println("Error: failed to send message");
			e.printStackTrace();
			System.exit(-1);
		}
		op.close();
		System.out.println("message sent ");
		
	}
	
	public synchronized void rendezvousEvent(RendezvousEvent event) {
		if (event.getType() == event.RDVCONNECT) {
			notify();
		}
	}
	
	public void buscarNodosModificacion(String identificador,long timestamp){
		System.out.println("Busqueda por identificador");
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.PEDIR_PERMISO,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.CONTENIDO,identificador,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.TIMESTAMP,timestamp+"",null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		int id = discoveryService.getRemoteAdvertisements(null, 
				DiscoveryService.ADV, 
				AdvertisementModificacion.IDENTIFICADOR_TAG, 
				"*"+identificador+"*",
				30,this);
		consultasPendientes.put(id, msg);
	}
	
	public void buscarPorIdentificador(String identificador){
		System.out.println("Busqueda por identificador");
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.DESCARGAR_ARCHIVO,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.CONTENIDO,identificador,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		int id = discoveryService.getRemoteAdvertisements(null, 
				DiscoveryService.ADV, 
				AdvertisementNodo.IDENTIFICADORES_TAG, 
				"*"+identificador+"*",
				1,this);
		consultasPendientes.put(id, msg);
		
		
	}
	
	public void buscarPorPalabraClave(String palabrasClave){
		System.out.println("Busqueda por palabra clave");
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.ARCHIVOS_CON_PALABRA_CLAVE,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.CONTENIDO,palabrasClave,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		int id = discoveryService.getRemoteAdvertisements(null, 
				DiscoveryService.ADV, 
				AdvertisementNodo.PALABRAS_CLAVE_TAG, 
				"*"+palabrasClave+"*",
				1,this);
		consultasPendientes.put(id, msg);
	}
	
	public void responderArchivosConPalabraClave(String contenido, String pipeId) throws Exception{
		OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeId), 0);
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.RESPUESTA_PALABRA_CLAVE,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.CONTENIDO,contenido,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		/*
		Message m2 = crearSobre(msg);
		outputPipe.send(m2.clone());
		outputPipe.close();
		*/
		int n = numMensaje++;
		mensajesPendientes.put(n, msg);
		solicitudAutenticacion(obtainPipeAdv(pipeId),n);
	}
	
	public void responderArchivoMasParecido(String identificador, long tamanio, String pipeId)throws Exception{
		OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeId), 0);
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.RESPUESTA_ARCHIVO_MAS_PARECIDO,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.CONTENIDO,identificador,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.TAMANIO,""+tamanio,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		
		/*
		Message m2 = crearSobre(msg);
		outputPipe.send(m2.clone());
		outputPipe.close();
		*/
		int n = numMensaje++;
		mensajesPendientes.put(n, msg);
		solicitudAutenticacion(obtainPipeAdv(pipeId),n);
	}
	
	public void enviarArchivo(Archivo archivo, String pipeId) throws Exception{
		
		OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeId), 0);
		Message msg = new Message();
		
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.ENVIAR_ARCHIVO,null);
		msg.addMessageElement(me);
		
		me = new InputStreamMessageElement(Nodo.CONTENIDO,MimeMediaType.AOS,new FileInputStream(nodo.desEncriptarArchivo(archivo.getArchivo())),null);
		msg.addMessageElement(me);
		
		me = new StringMessageElement(Nodo.IDENTIFICADOR,archivo.getIdentificador(),null);
		msg.addMessageElement(me);
		
		me = new InputStreamMessageElement(Nodo.FIRMA_DIGITAL,MimeMediaType.AOS,new ByteArrayInputStream(archivo.getFirma()),null);
		msg.addMessageElement(me);
		
		me = new StringMessageElement(Nodo.DUENO_ARCHIVO,archivo.getDuenoArchivo(),null);
		msg.addMessageElement(me);
		
		String palabrasClave = "";
		for (String pClave : archivo.getPalabrasClave()) {
			palabrasClave+=pClave+",";
		}
		me = new StringMessageElement(Nodo.PALABRAS_CLAVE,palabrasClave,null);
		msg.addMessageElement(me);
		
		me = new StringMessageElement(Nodo.NOMBRE,archivo.getArchivo().getName(),null);
		msg.addMessageElement(me);
		
		/*
		Message m2 = crearSobre(msg);
		outputPipe.send(m2.clone());
		outputPipe.close();
		*/
		int n = numMensaje++;
		mensajesPendientes.put(n, msg);
		solicitudAutenticacion(obtainPipeAdv(pipeId),n);
	}
	
	public void refrescarAdvertisement(ArrayList<Archivo> archivos){
		String identificadores = "," , palabrasClave = "";
		for (Archivo archivo : archivos) {
			identificadores+=archivo.getIdentificador()+",";
			palabrasClave+=archivo.getPalabrasClave()+",";
		}
		advertisementNodo.setIdentificadoresDocumento(identificadores);
		advertisementNodo.setPalabrasClave(palabrasClave);
		try{
			discoveryService.publish(advertisementNodo);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public PipeAdvertisement obtainPipeAdv(String pipeId) throws Exception{
		PipeAdvertisement pipeAdv = (PipeAdvertisement) AdvertisementFactory
		.newAdvertisement(PipeAdvertisement.getAdvertisementType());
		
		System.out.println("PipeId:"+pipeId);
		PipeID id = (PipeID) IDFactory.fromURI(new URI(pipeId));
		pipeAdv.setPipeID(id);
		pipeAdv.setName("Mi primer pipe");
		pipeAdv.setType(PipeService.UnicastType);
		return pipeAdv;
	}
	
	public void buscarArchivoPorTamanio(long tamanio) {
		System.out.println("Busqueda por palabra clave");
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.ARCHIVO_MAS_PARECIDO,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.CONTENIDO,""+tamanio,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		int id = discoveryService.getRemoteAdvertisements(null, 
				DiscoveryService.ADV, 
				null, 
				null,
				10,this);
		consultasPendientes.put(id, msg);
		
	}
	
	public void darPermiso(String identificador, String pipeId) throws Exception{
		OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeId), 0);
		Message msg = new Message();
		
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.CONCEDER_PERMISO,null);
		msg.addMessageElement(me);
		
		me = new StringMessageElement(Nodo.CONTENIDO,identificador,null);
		msg.addMessageElement(me);
		
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		
		int n = numMensaje++;
		mensajesPendientes.put(n, msg);
		solicitudAutenticacion(obtainPipeAdv(pipeId),n);
		/*
		Message m2 = crearSobre(msg);
		outputPipe.send(m2.clone());
		outputPipe.close();
		*/
	}
	
	public void publicarAdvertisementModificacion(long timestamp,String identificador){
		try{
			advertisementModificacion= new AdvertisementModificacion();
			advertisementModificacion.setIdentificadorArchivo(identificador);
			advertisementModificacion.setTimestamp(timestamp);
			advertisementModificacion.setPipeAdvertisement(inputPipe);
			discoveryService.publish(advertisementModificacion,Nodo.TTL_ADVERTISEMENT_MODIFICACION,Nodo.TTL_ADVERTISEMENT_MODIFICACION);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static class Instantiator implements AdvertisementFactory.Instantiator{

        public String getAdvertisementType() {
           return "AdvertisementPeer";
        }

        public Advertisement newInstance() {
            return new AdvertisementNodo();
        }

        public Advertisement newInstance(Element root) {
            return new AdvertisementNodo(root);
        }

    }


	public static class InstantiatorModificacion implements AdvertisementFactory.Instantiator{

        public String getAdvertisementType() {
           return "AdvertisementModificacion";
        }

        public Advertisement newInstance() {
            return new AdvertisementModificacion();
        }

        public Advertisement newInstance(Element root) {
            return new AdvertisementModificacion(root);
        }

    }

	public void responderGuardarEstado(String pipeInf, File archivoEstado) throws Exception
	{
		//SE ENVIA MI ESTADO 
		OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeInf), 0);
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.RESPUESTA_GUARDAR_ESTADO,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.NOMBRE, nodo.getNombre(),null);
		msg.addMessageElement(me);
		me = new InputStreamMessageElement(Nodo.CONTENIDO,MimeMediaType.AOS, new FileInputStream(archivoEstado),null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		
		/*
		Message m2 = crearSobre(msg);
		outputPipe.send(m2.clone());
		outputPipe.close();
		*/
		int n = numMensaje++;
		mensajesPendientes.put(n, msg);
		solicitudAutenticacion(obtainPipeAdv(pipeInf),n);
	}

	public void enviarGuardarEstado() throws Exception
	{
		//OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeInfo), 0);
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.GUARDAR_ESTADO,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.NOMBRE, nodo.getNombre(),null);
		msg.addMessageElement(me);
		//TODO: Meter ids de peers
		/*me = new StringMessageElement(Nodo.CONTENIDO,"METER IDS DE PEERS",null);
		msg.addMessageElement(me);*/
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		
		int id = discoveryService.getRemoteAdvertisements(null, 
				DiscoveryService.ADV, 
				AdvertisementNodo.PALABRAS_CLAVE_TAG, 
				"*",
				1,this);
		consultasPendientes.put(id, msg);
		
		/*outputPipe.send(msg);
		outputPipe.close();*/
	}
	
	public void enviarCertificadoDigital(byte[] llave, String pipeId) throws Exception{
		
		OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeId), 0);
		Message msg = new Message();
		
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.CERTIFICADO_DIGITAL,null);
		msg.addMessageElement(me);
		
		me = new InputStreamMessageElement(Nodo.CONTENIDO,MimeMediaType.AOS,new ByteArrayInputStream(llave),null);
		msg.addMessageElement(me);
		
		/*
		Message m2 = crearSobre(msg);
		outputPipe.send(m2.clone());
		outputPipe.close();
		*/
		int n = numMensaje++;
		mensajesPendientes.put(n, msg);
		solicitudAutenticacion(obtainPipeAdv(pipeId),n);
	}
	
	public void obtenerLlavePublica(String pipeId) throws Exception{
		
		OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeId), 0);
		Message msg = new Message();
		
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.OBTENER_CERTIFICADO_DIGITAL,null);
		msg.addMessageElement(me);
		
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		
		/*
		Message m2 = crearSobre(msg);
		outputPipe.send(m2.clone());
		outputPipe.close();
		*/
		int n = numMensaje++;
		mensajesPendientes.put(n, msg);
		solicitudAutenticacion(obtainPipeAdv(pipeId),n);
	}
	
	private void agregarCertificadoDigital(Message msg) throws Exception{
		MessageElement me = new InputStreamMessageElement(Nodo.CERTIFICADO_DIGITAL,
				MimeMediaType.AOS,
				new ByteArrayInputStream(nodo.getCertificadoDigitalTransmision()),null);
		msg.addMessageElement(me);
	}
	
	private byte[] encriptarMensaje(Message msj,Key key) throws Exception{
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream out = new ObjectOutputStream(bos);
		out.writeObject(msj);
		out.close();
		return nodo.encriptar(bos.toByteArray(), key);
	}
	

	
	private Message crearSobre(Message msj,Key key,InputStream llavePublica,Key DHkey) throws Exception{
		
		byte[] encriptado = encriptarMensaje(msj,key);
		Message m = new Message();
		
		MessageElement me = new InputStreamMessageElement(Nodo.CONTENIDO,MimeMediaType.AOS,new ByteArrayInputStream(encriptado),null);
		m.addMessageElement(me);
		agregarCertificadoDigital(m);
		me = new InputStreamMessageElement(Nodo.LLAVE,MimeMediaType.AOS,llavePublica,null);
		m.addMessageElement(me);
		byte[] mac = nodo.generarMAC(encriptado, DHkey);
		me = new InputStreamMessageElement(Nodo.MAC,MimeMediaType.AOS,new ByteArrayInputStream(mac),null);
		m.addMessageElement(me);
		me = new StringMessageElement(Nodo.COMANDO,Nodo.MENSAJE,null);
		m.addMessageElement(me);
		return m;
	}
	
	public void solicitudAutenticacion(PipeAdvertisement adv, int n) throws Exception{
		OutputPipe outputPipe = pipeService.createOutputPipe(adv, 0);
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.SOLICITUD_AUTENTICACION,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.NUM_CONSULTA,""+n,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		
		outputPipe.send(msg.clone());
		outputPipe.close();
	}
	
	public void enviarAutenticacion(InputStream certificado, InputStream llavePublicaDH, int n, String pipeId) throws Exception{
		Message msg = new Message();
		MessageElement me = new StringMessageElement(Nodo.COMANDO,Nodo.AUTENTICACION,null);
		msg.addMessageElement(me);
		me = new InputStreamMessageElement(Nodo.CERTIFICADO_DIGITAL, MimeMediaType.AOS, certificado, null);
		msg.addMessageElement(me);
		me = new InputStreamMessageElement(Nodo.LLAVE, MimeMediaType.AOS, llavePublicaDH, null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.NUM_CONSULTA,""+n,null);
		msg.addMessageElement(me);
		me = new StringMessageElement(Nodo.PIPE_INFO,inputPipe.getID().toString(),null);
		msg.addMessageElement(me);
		
		OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeId), 0);
		outputPipe.send(msg.clone());
		outputPipe.close();
	}
	
	public void envioMensaje(int numConsulta,Key key,String pipeId, InputStream llavePublicaDH,Key DHkey) throws Exception{
		Message m = crearSobre(mensajesPendientes.get(numConsulta),key,llavePublicaDH,DHkey);
		
		OutputPipe outputPipe = pipeService.createOutputPipe(obtainPipeAdv(pipeId), 0);
		outputPipe.send(m.clone());
		outputPipe.close();
	}
}
